package org.activequant.core.domainmodel.marketscanner;
import static org.activequant.util.tools.IdentityUtils.equalsTo;
import static org.activequant.util.tools.IdentityUtils.safeCompare;
import static org.activequant.util.tools.IdentityUtils.safeHashCode;

import org.activequant.core.types.TimeStamp;
/**
 * MarketScanChange extends ScanDataEntity&lt;MarketScanChange&gt;. Holds the following associated variables:
 * <ul>
 * <li>previousScanTime(TimeStamp)</li>
 * <li>instrumentSpecificationDetails(InstrumentSpecificationDetails)</li>
 * <li>changeType(ChangeType)</li>
 * <li>numberOfInstruments(int)</li>
 * <li>amplitude(int)</li>
 * <li>changeInterval(long)</li>
 * <li>magnitude(double)</li>
 * <li>previousPosition(int)</li>
 * <li>currentPosition(int)</li>
 * </ul>
 * Inherits the following variables:
 * <ul>
 * <li>id(Long)</li>
 * <li>scanCriteria(ScanCriteria)</li>
 * <li>timeStamp(TimeStamp)</li>
 * </ul>
 * It also defines the ChangeType enum type.
 * @author Dimitar
 *
 */
public class MarketScanChange extends ScanDataEntity<MarketScanChange>{

	private static final long serialVersionUID = 3127020478834242874L;
	/**
	 * private TimeStamp previousScanTime;<br/>
	 * this is the last known time before the change (delivered from IB)
	 */
	private TimeStamp previousScanTime;
	/**
	 * private InstrumentSpecificationDetails instrumentSpecificationDetails;
	 */
	private InstrumentSpecificationDetails instrumentSpecificationDetails;
	/**
	 * private ChangeType changeType;
	 */
	private ChangeType changeType;
	/**
	 * private int numberOfInstruments;
	 */
	private int numberOfInstruments;
	/**
	 * private int amplitude;
	 */
	private int amplitude;
	/**
	 * private long changeInterval;
	 */
	private long changeInterval;
	/**
	 * private double magnitude;<br/>
	 * amplitude/numberOfInstruments - relative measure
	 */
	private double magnitude;
	/**
	 * private int previousPosition;
	 */
	private int previousPosition;
	/**
	 * private int currentPosition;
	 */
	private int currentPosition;
	
	public int getPreviousPosition() {
		return previousPosition;
	}
	public void setPreviousPosition(int previousPosition) {
		this.previousPosition = previousPosition;
	}
	public int getCurrentPosition() {
		return currentPosition;
	}
	public void setCurrentPosition(int currentPosition) {
		this.currentPosition = currentPosition;
	}
	/**
	 * returns the associated previousScanTime(TimeStamp)<br/>
	 * this is the last known time before the change (delivered from IB)
	 * @return
	 */
	public TimeStamp getPreviousScanTime() {
		return previousScanTime;
	}
	/**
	 * Sets the associated previousScanTime(TimeStamp) with the given previousScanTime(TimeStamp)
	 * @param previousScanTime
	 */
	public void setPreviousScanTime(TimeStamp previousScanTime) {
		this.previousScanTime = previousScanTime;
	}
	/**
	 * returns the associated instrumentSpecificationDetails(InstrumentSpecificationDetails)
	 * @return
	 */
	public InstrumentSpecificationDetails getInstrumentSpecificationDetails() {
		return instrumentSpecificationDetails;
	}
	/**
	 * Sets the associated instrumentSpecificationDetails(InstrumentSpecificationDetails) with the given instrumentSpecificationDetails(InstrumentSpecificationDetails)
	 * @param instrumentSpecificationDetails
	 */
	public void setInstrumentSpecificationDetails(InstrumentSpecificationDetails instrumentSpecificationDetails) {
		this.instrumentSpecificationDetails = instrumentSpecificationDetails;
	}
	/**
	 * returns the associated changeType(ChangeType) enum
	 * @return
	 */
	public ChangeType getChangeType() {
		return changeType;
	}
	/**
	 * sets the associated changeType(ChangeType) enum with the given changeType(ChangeType)
	 * @param changeType
	 */
	public void setChangeType(ChangeType changeType) {
		this.changeType = changeType;
	}
	/**
	 * returns the associated numberOfInstruments(int)
	 * @return
	 */
	public int getNumberOfInstruments() {
		return numberOfInstruments;
	}
	/**
	 * sets the associated numberOfInstruments(int) with the given numberOfInstruments(int)
	 * @param numberOfInstruments
	 */
	public void setNumberOfInstruments(int numberOfInstruments) {
		this.numberOfInstruments = numberOfInstruments;
	}
	/**
	 * returns the associated amplitude(int)
	 * @return
	 */
	public int getAmplitude() {
		return amplitude;
	}
	/**
	 * sets the associated amplitude(int) with the given amplitude(int)
	 * @param amplitude
	 */
	public void setAmplitude(int amplitude) {
		this.amplitude = amplitude;
	}
	/**
	 * returns the associated changeInterval(long)
	 * @return
	 */
	public long getChangeInterval() {
		return changeInterval;
	}
	/**
	 * sets the associated changeInterval(long) with the given changeInterval(long)
	 * @param changeInterval
	 */
	public void setChangeInterval(long changeInterval) {
		this.changeInterval = changeInterval;
	}
	
	public double getMagnitude() {
		return magnitude;
	}
	public void setMagnitude(double magnitude) {
		this.magnitude = magnitude;
	}
	
	/**
	 * An enum type. Defines the following values:
	 * <ul>
	 * <li>INSTRUMENT_ADDED("We have an instrument which wasn't on the previous scan")</li>
	 * <li>INSTRUMENT_REMOVED("An instrument which was on the previous scan, is not there anymore in the new scan")</li>
	 * <li>INSTRUMENT_MOVED_UP("An instrument which was on the previous scan, is now a few positions higher in the new scan")</li>
	 * <li>INSTRUMENT_MOVED_DOWN("An instrument which was on the previous scan, is now a few positions lower in the new scan")</li>
	 * </ul>
	 * It also holds the following associated variable:
	 * <ul>
	 * <li>description(String)</li>
	 * </ul>
	 * @author Dimitar
	 *
	 */
	public enum ChangeType{		
		
		INSTRUMENT_ADDED("We have an instrument which wasn't on the previous scan"),
		INSTRUMENT_REMOVED("An instrument which was on the previous scan, is not there anynore in the new scan"),
		INSTRUMENT_MOVED_UP("An instrument which was on the previous scan, is now a few positions higher in the new scan"),
		INSTRUMENT_MOVED_DOWN("An instrument which was on the previous scan, is now a few positions lower in the new scan");
		
		ChangeType(String description) {
			this.description = description;
		}
		private String description;		
		public String toString() {
			return name();
		}
		/**
		 * Returns the ChangeType enum whose name(String) matches the given value(String).
		 * Throws an IllegalArgumentException if it can't find such enum
		 * @param value
		 * @return
		 */
		public static ChangeType toClass(String value) {
			for(ChangeType symbol: values()) {
				if(symbol.name().equals(value)) {
					return symbol;
				}
			}
			throw new IllegalArgumentException("Value '"+value+"' not defined as constant.");
		}
	}
	
	@Override
	public MarketScanChange clone() {
		MarketScanChange clone=new MarketScanChange();
		clone.setPreviousScanTime(previousScanTime);
		clone.setTimeStamp(getTimeStamp());
		clone.setInstrumentSpecificationDetails(instrumentSpecificationDetails);
		clone.setChangeType(changeType);
		clone.setNumberOfInstruments(numberOfInstruments);
		clone.setAmplitude(amplitude);
		clone.setChangeInterval(changeInterval);
		clone.setMagnitude(magnitude);
		clone.setScanCriteria(getScanCriteria());
		return clone;
	}
	
	@Override
	public String toString() {
		return " MarketScanChange: "+this.getChangeType()+" timeStamp: "+this.getTimeStamp();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int hashCode() {
		// ATTENTION: keep in sync with compareTo();
		return safeHashCode(this.getChangeType()) + safeHashCode(this.getScanCriteria())+ safeHashCode(this.getInstrumentSpecificationDetails())+safeHashCode(this.getTimeStamp());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean equals(Object other) {
		// NOTE: delegates to compareTo()
		return equalsTo(this, other);
	}
	
	/**
	 * {@inheritDoc}
	 */
	public int compareTo(MarketScanChange other) {
		// ATTENTION: keep in sync with hashCode();
		int rc;
		rc = safeCompare(this.getChangeType(), other.getChangeType());
		if (rc != 0) return rc;
		rc = safeCompare(this.getScanCriteria(), other.getScanCriteria());
		if (rc != 0) return rc;
		rc = safeCompare(this.getInstrumentSpecificationDetails(), other.getInstrumentSpecificationDetails());
		if (rc != 0) return rc;
		rc = safeCompare(this.getTimeStamp(), other.getTimeStamp());
		if (rc != 0) return rc;
		return rc;
	}

}


